package it.okkam.webid.model;

import java.io.InputStream;

import org.bouncycastle.asn1.x509.UserNotice;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.ResultSetFormatter;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.util.FileManager;

import edu.mit.simile.longwell.LongwellServer;

/**
 * This class contains methods for authenticating and authorizing user based on
 * the webid.
 * 
 * 
 */
public class VerifyWebID {
	static Model model;

	/**
	 * check if the webid is in the allowed user groups, in the user management
	 * datasets
	 * 
	 * @param webID
	 *            the webid from the certificate
	 * @param fileName
	 *            the ttl file / rdf store of user management dataset
	 * @return true or false
	 */
	public boolean isAllowed(String webID, String fileName) {
		boolean allowed = false;
		// ServletContext sc = getServletContext();
		InputStream in = FileManager.get().open(fileName);
		if (in == null) {
			System.out.println("File Not Found");
		} else {
			// Create the input model. Models different from the default one
			// import also the
			// rdf and rdf-schema axioms. The input model usually comes with
			// blank nodes.
			model = LongwellServer.getModelForAuthentication();//ModelFactory.createDefaultModel();
			// read the RDF/TURTLE file
			model.read(in, null, "TURTLE");

		}
		if (model != null) {
			Resource sub = model.createResource(webID);
			Property prop = model
					.createProperty("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
			RDFNode pred = model
					.createResource("http://xmlns.com/foaf/0.1#Person");
			String prefix = "PREFIX foaf: <http://xmlns.com/foaf/0.1/> "
					+ "PREFIX : <http://www.semanticweb.org/ontologies/2011/9/Rivela-Flussi.owl#> "
					+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> ";
			// check webid if it is in the rivela user group
			String queryString = prefix + '\n'
					+ "ask { :rivela_user a foaf:Group ; " + "foaf:member <"
					+ webID + "> . } ";

			System.out.println(queryString);

			Query query = QueryFactory.create(queryString);
			QueryExecution qexec = QueryExecutionFactory.create(query, model);

			allowed = qexec.execAsk();

			qexec.close();
		}

		return allowed;
	}

	/**
	 * authenticate a user who tried to login with a certificate. The modulus in
	 * the certificate will be compared with the one in the webid rdf data store
	 * 
	 * @param webID
	 *            the webID extracted from the certificate
	 * @param modulus
	 *            modulus of the public key
	 * @param exponent
	 *            exponent of the public key
	 * @param fileName
	 *            // file name (for test purpose) SPARQL end point of the rdf
	 *            store
	 * @return
	 */
	public boolean isAuthenticated(String webID, String modulus,
			String exponent, String fileName) {
		// this will be used if the webserver hosting rivela is running behind a
		// proxy server
		if(LongwellServer.getProxyHost()!=null && LongwellServer.getProxyHost().length()>0)
			System.setProperty("http.proxyHost", LongwellServer.getProxyHost());
		if(LongwellServer.getProxyPort()!=null && LongwellServer.getProxyPort().length()>0)
			System.setProperty("http.proxyPort", LongwellServer.getProxyPort());

		boolean allowed = false;

		FileManager fm = new FileManager();
		InputStream in = fm.get().open(fileName);
		if (in == null) {
			System.out.println("File Not Found");
		} else {
			model = LongwellServer.getModelForAuthentication();
			model.read(in, null, "RDF/XML");

		}
		if (model != null) {

			Property prop = model
					.createProperty("http://www.w3.org/ns/auth/cert#key");
			StmtIterator it = model.listStatements();

			Property propexponent = model
					.createProperty("http://www.w3.org/ns/auth/cert#exponent");
			Property propemodulus = model
					.createProperty("http://www.w3.org/ns/auth/cert#modulus");

			// varities of
			Property propexponent2 = model
					.createProperty("http://www.w3.org/ns/auth/cert#decimal");
			Property propemodulus2 = model
					.createProperty("http://www.w3.org/ns/auth/cert#hex");

			String modulustemp = null;
			String exponenttemp = null;
			boolean modulusfound = false, exponentfound = false;
			while (it.hasNext()) {
				Statement statment = it.next();
				Resource subject = statment.getSubject();
				Property predicate = statment.getPredicate();
				RDFNode object = statment.getObject();
				if (propemodulus.equals(predicate)
						|| propemodulus2.equals(predicate)) {
					modulustemp = object.toString();
					modulusfound = true;
					if (exponentfound)
						break;
				}

				if (propexponent.equals(predicate)
						|| propexponent2.equals(predicate)) {
					exponenttemp = object.toString();
					exponentfound = true;
					if (modulusfound)
						break;
				}

			}

			// remove data type attachments from the modulus and exponents
			if (modulustemp.contains("\"")) {
				modulustemp = modulustemp.toString()
						.substring(0, modulustemp.toString().indexOf("\""))
						.trim();
			}

			if (modulustemp.contains("^")) {
				modulustemp = modulustemp.toString()
						.substring(0, modulustemp.toString().indexOf("^"))
						.trim();
			}

			if (exponenttemp.contains("\"")) {
				exponenttemp = exponenttemp.toString()
						.substring(0, exponenttemp.toString().indexOf("\""))
						.trim();
			}

			if (exponenttemp.contains("^")) {
				exponenttemp = exponenttemp.toString()
						.substring(0, exponenttemp.toString().indexOf("^"))
						.trim();
			}

			// exponenttemp =
			// exponenttemp.toString().substring(0,exponenttemp.toString().indexOf("^")).trim();

			if (modulustemp.equals(modulus.trim())
					&& exponenttemp.equals(exponent.trim())) {
				allowed = true;
			}

		}

		return allowed;
	}

	/**
	 * Returns the user name associated with the webid, if the webid is already
	 * available in the rdf store
	 * 
	 * @param webID
	 *            webID of the user
	 * @param fileName
	 *            the ttl file / rdf store for user management
	 * @return
	 */

	public static boolean isAdmin(String userName, String fileName) {
		boolean allowed = false;
		// ServletContext sc = getServletContext();
		InputStream in = FileManager.get().open(fileName);
		if (in == null) {
			System.out.println("File Not Found");
		} else {
			// Create the input model. Models different from the default one
			// import also the
			// rdf and rdf-schema axioms. The input model usually comes with
			// blank nodes.
			//model = LongwellServer.getModelForAuthentication();
			// read the RDF/TURTLE file
			//model.read(in, null, "TURTLE");
			model = LongwellServer.getBCCDataset().getNamedModel("http://www.provincia.tn.it/bcc/resource/bcc-utenti");

		}
		if (model != null) {
			String prefix = "PREFIX foaf: <http://xmlns.com/foaf/0.1/> "
					+ "PREFIX : <http://www.semanticweb.org/ontologies/2011/9/Rivela-Flussi.owl#> "
					+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> ";

			String queryString = prefix + '\n'
					+ "ask { :rivela_admin a foaf:Group ; " +
					"foaf:member ?sub  ." +
					"?sub foaf:nickname \""+userName +"\" .}";

			Query query = QueryFactory.create(queryString);
			QueryExecution qexec = QueryExecutionFactory.create(query, model);

			allowed = qexec.execAsk();

			qexec.close();
		}

		return allowed;
	}

	public String getUserName(String webID, String fileName) {

		String queryString = "PREFIX foaf: <http://xmlns.com/foaf/0.1/> "
				+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> "
				+ "SELECT ?username " + "WHERE {" + "      <" + webID
				+ "> foaf:nickname ?username . " + "      }";

		Query query = QueryFactory.create(queryString);

		QueryExecution qe = QueryExecutionFactory.create(query, model);
		ResultSet results = qe.execSelect();

		QuerySolution solution = results.next();
		String userName = solution.get("username").toString();

		qe.close();

		return userName;

	}
}
